import base64
import os.path
import re
from collections import OrderedDict
from pathlib import Path

import cv2
import numpy as np
from werkzeug.utils import secure_filename

import config

PHOTO_FOLDER = Path(config.get_config('FACE_DATA_PATH') + '/data/photo')
PHOTO_FOLDER.mkdir(parents=True, exist_ok=True)
VIDEO_FOLDER = Path(config.get_config('FACE_DATA_PATH') + '/data/video')
VIDEO_FOLDER.mkdir(parents=True, exist_ok=True)

FACENET_INPUT_SIZE = 160


def split_data_ext(blob):
    result = re.search("data:image/(?P<ext>.*?);base64,(?P<data>.*)", blob, re.DOTALL)
    if result:
        ext = result.groupdict().get("ext")
        data = result.groupdict().get("data")
    else:
        raise ValueError("Do not parse!")
    return data, ext


def save_photo(data: str, file_name: str) -> bool:
    """Store file to disk, the name is "name-cell phone number-index.webp"
    :param data: webp data
    :param file_name: username
    :return:
    """
    image = base64.urlsafe_b64decode(data)
    file_path = PHOTO_FOLDER / file_name
    with open(file_path, 'wb') as f:
        f.write(image)
    return True


def remove_photo(file_name: str) -> bool:
    file_path = PHOTO_FOLDER / file_name
    if file_path.exists():
        os.remove(file_path)
    return True


def image_to_base64(image_path) -> str:
    """Transfer imagee to base64 string"""
    ext = image_path.split('.')[-1]
    with open(image_path, 'rb') as f:
        img = f.read()
    image_base64 = base64.b64encode(img).decode()
    image_base64_format = "data:image/{ext};base64,{data}".format(ext=ext, data=image_base64)
    return image_base64_format


def decode_image(base64_data: str):
    image = base64.b64decode(base64_data.split(',')[1])
    image = np.frombuffer(image, np.uint8)
    return cv2.imdecode(image, cv2.IMREAD_COLOR)


def _isotropically_resize_image(image, size, interpolation_down=cv2.INTER_AREA, interpolation_up=cv2.INTER_CUBIC):
    """Ensure min side >= size"""
    h, w = image.shape[:2]
    if min(w, h) == size:
        return image
    if h < w:
        scale = size / h
        w = w * scale
        h = size
    else:
        scale = size / w
        h = h * scale
        w = size
    interpolation = interpolation_up if scale > 1 else interpolation_down
    resized = cv2.resize(image, (int(w), int(h)), interpolation=interpolation)
    return resized


def resize_image_to(image: np.ndarray, size) -> np.ndarray:
    image = _isotropically_resize_image(image, size)
    height, width = image.shape[:2]
    x_center, y_center = height // 2, width // 2
    half_size = size // 2
    x1, y1, x2, y2 = x_center - half_size, y_center - half_size, x_center + half_size, y_center + half_size
    assert x2 - x1 == size and y2 - y1 == size
    cropped = image[x1:x2, y1:y2]
    return cropped


def resize_blob_to(blob: str, size=160) -> np.ndarray:
    """
    resize image to ndarray of rgb image
    :param blob: image blob from front
    :param size: target size
    :return: ndarray of rgb image
    """
    image = decode_image(blob)
    return resize_image_to(image=image, size=size)


def resize_image_path_to(image_path: str, size=160) -> np.ndarray:
    """
    resize image to ndarray of rgb image
    :param image_path: image path
    :param size: target size
    :return: ndarray of rgb image
    """
    image = cv2.imread(image_path, cv2.IMREAD_COLOR)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    return resize_image_to(image=image, size=size)


def save_video(video, video_name):
    """Store file to disk, the name is "name-timestamp.webp"
    :param video: video
    :param video_name: filename
    :return:
    """
    video_name = secure_filename(video_name)
    file_path = VIDEO_FOLDER / video_name
    video.save(file_path)
    return True


def get_video_frames_and_fps(video):
    capture = cv2.VideoCapture(video)
    fps = capture.get(cv2.CAP_PROP_FPS)
    frames_num = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
    frames = OrderedDict()
    for i in range(frames_num):
        capture.grab()
        success, frame = capture.retrieve()
        if not success:
            continue
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # frame = Image.fromarray(frame)
        # size = (frame.size[0] // 2, frame.size[1] // 2)
        # frame = frame.resize(size=size)
        frames[i] = frame
    return frames, fps


def remove_video(video_name):
    video_path = VIDEO_FOLDER / video_name
    if video_path.exists():
        os.remove(video_path)
    return True
